/*
 * Copyright 2008 Nils Adermann
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Object.h"
#include "Identifier.h"
#include "String.h"
#include "Number.h"

using namespace JSON;

Object::Object() :
	Value(OBJECT)
{
	map = new std::map<Identifier, Value*>();
}

Object::Object(const Object& o) :
	Value(o)
{
	map = new std::map<Identifier, Value*>();
	*map = *o.getMap();
}

Object::~Object()
{
	// the values will be deleted too
	for (std::map<Identifier, Value*>::iterator it = begin(); it != end(); ++it)
	{
		if (it->second)
		{
			delete it->second;
		}
	}
	delete map;
}

bool Object::empty() const
{
	return map->empty();
}

size_t Object::size() const
{
	return map->size();
}


std::map<Identifier, Value*>::iterator Object::begin()
{
	return map->begin();
}

std::map<Identifier, Value*>::iterator Object::end()
{
	return map->end();
}

std::map<Identifier, Value*>::const_iterator Object::begin() const
{
	return map->begin();
}

std::map<Identifier, Value*>::const_iterator Object::end() const
{
	return map->end();
}


Object& Object::operator=(const Object& o)
{
	if (&o != this)
	{
		delete map;
		map = new std::map<Identifier, Value*>();
		*map = *o.getMap();
	}
	return *this;
}


Value*& Object::operator[](const Identifier& key)
{
	return (*map)[key];
}

Value*& Object::operator[](const Number& key)
{
	Identifier i(key);
	return (*this)[i];
}

Value*& Object::operator[](const String& key)
{
	Identifier i(key);
	return (*this)[i];
}

Value*& Object::operator[](const char* key)
{
	String i(key);
	return (*this)[i];
}

Value*& Object::operator[](int64_t key)
{
	Number i(key);
	return (*this)[i];
}

Value*& Object::operator[](double key)
{
	Number i(key);
	return (*this)[i];
}


const Value* Object::operator[](const Identifier& key) const
{
	return (*map)[key];
}

const Value* Object::operator[](const Number& key) const
{
	Identifier i(key);
	return (*this)[i];
}

const Value* Object::operator[](const String& key) const
{
	Identifier i(key);
	return (*this)[i];
}

const Value* Object::operator[](const char* key) const
{
	String i(key);
	return (*this)[i];
}

const Value* Object::operator[](int64_t key) const
{
	Number i(key);
	return (*this)[i];
}

const Value* Object::operator[](double key) const
{
	Number i(key);
	return (*this)[i];
}


std::map<Identifier, Value*>::iterator Object::find(const Identifier& key)
{
	return map->find(key);
}

std::map<Identifier, Value*>::iterator Object::find(const String& key)
{
	Identifier i(key);
	return find(i);
}

std::map<Identifier, Value*>::iterator Object::find(const Number& key)
{
	Identifier i(key);
	return find(i);
}

std::map<Identifier, Value*>::iterator Object::find(const char* key)
{
	String i(key);
	return find(i);
}

std::map<Identifier, Value*>::iterator Object::find(int64_t key)
{
	Number i(key);
	return find(i);
}

std::map<Identifier, Value*>::iterator Object::find(double key)
{
	Number i(key);
	return find(i);
}


std::map<Identifier, Value*>::const_iterator Object::find(const Identifier& key) const
{
	return map->find(key);
}

std::map<Identifier, Value*>::const_iterator Object::find(const String& key) const
{
	Identifier i(key);
	return find(i);
}

std::map<Identifier, Value*>::const_iterator Object::find(const Number& key) const
{
	Identifier i(key);
	return find(i);
}

std::map<Identifier, Value*>::const_iterator Object::find(const char* key) const
{
	String i(key);
	return find(i);
}

std::map<Identifier, Value*>::const_iterator Object::find(int64_t key) const
{
	Number i(key);
	return find(i);
}

std::map<Identifier, Value*>::const_iterator Object::find(double key) const
{
	Number i(key);
	return find(i);
}


std::pair<std::map<Identifier, Value*>::iterator, bool> Object::insert(const Identifier& key, Value* val)
{
	return map->insert(std::pair<Identifier, Value*>(key, val));
}

std::pair<std::map<Identifier, Value*>::iterator, bool> Object::insert(const String& key, Value* val)
{
	Identifier i(key);
	return insert(i, val);
}

std::pair<std::map<Identifier, Value*>::iterator, bool> Object::insert(const Number& key, Value* val)
{
	Identifier i(key);
	return insert(i, val);
}

std::pair<std::map<Identifier, Value*>::iterator, bool> Object::insert(const char* key, Value* val)
{
	String i(key);
	return insert(i, val);
}

std::pair<std::map<Identifier, Value*>::iterator, bool> Object::insert(int64_t key, Value* val)
{
	Number i(key);
	return insert(i, val);
}

std::pair<std::map<Identifier, Value*>::iterator, bool> Object::insert(double key, Value* val)
{
	Number i(key);
	return insert(i, val);
}


void Object::erase(const Identifier& key)
{
	std::map<Identifier, Value*>::iterator position = find(key);

	if (position->second)
	{
		delete position->second;
		position->second = NULL;
	}

	map->erase(position);
}

void Object::erase(const String& key)
{
	Identifier i(key);
	erase(i);
}

void Object::erase(const Number& key)
{
	Identifier i(key);
	erase(i);
}

void Object::erase(const char* key)
{
	String i(key);
	erase(i);
}

void Object::erase(int64_t key)
{
	Number i(key);
	erase(i);
}

void Object::erase(double key)
{
	Number i(key);
	erase(i);
}


std::map<Identifier, Value*>* Object::getMap()
{
	return map;
}

const std::map<Identifier, Value*>* Object::getMap() const
{
	return map;
}

Object& Object::toObject()
{
	return *this;
}

const Object& Object::toObject() const
{
	return *this;
}

void Object::toJSON(UnicodeString* u) const
{
	u->append("{");

	for (std::map<Identifier, Value*>::const_iterator it = begin(); it != end(); ++it)
	{
		if (it != begin())
		{
			u->append(", ");
		}
		
		it->first.toJSON(u);
		u->append(": ");
		if (it->second)
		{
			it->second->toJSON(u);
		}
		else
		{
			u->append("null");
		}
	}

	u->append("}");
}
